package org.pblue.appengine;

import java.util.ArrayList;
import java.util.List;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Transaction;

public final class AppengineDataManager {
  private static PersistenceManagerFactory mPMFInstance;
  
  private PersistenceManager mPersistenceManager;
  private Transaction mTransaction;
  private List<Object> mCacheKeysInTransactions;
  
  public static PersistenceManager getPersistenceManager() {
    // create pm factory instance if needed
    if (mPMFInstance == null) {
      mPMFInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional");
    }
    
    PersistenceManager pm = mPMFInstance.getPersistenceManager();
    pm.setDetachAllOnCommit(true);
    
    return pm;
  }
  
  public PersistenceManager getCurrentPersistenceManager() {
    if (mPersistenceManager == null) {
      mPersistenceManager = AppengineDataManager.getPersistenceManager();
    }
    return mPersistenceManager;
  }
  
  public Transaction getCurrentTransaction() {
    if (mTransaction == null) {
      mTransaction = getCurrentPersistenceManager().currentTransaction();
    }
    return mTransaction;
  }
  
  public static AppengineDataManager open() {
    return new AppengineDataManager();
  }
  
  public void begin() {
    if (mTransaction == null) {
      mTransaction = getCurrentPersistenceManager().currentTransaction();
    }
    
    if (mCacheKeysInTransactions != null) {
      mCacheKeysInTransactions = null;
    }
    
    mTransaction.begin();
  }
  
  public void addCacheKeyToTransactions(Object pCacheKey) {
    if (mCacheKeysInTransactions == null) {
      mCacheKeysInTransactions = new ArrayList<Object>();
    }
    
    mCacheKeysInTransactions.add(pCacheKey);
  }
  
  public void rollback() {
    if (mTransaction != null && mTransaction.isActive()) {
      mTransaction.rollback();
    }
    
    if (mCacheKeysInTransactions != null) {
      for (Object cacheKey : mCacheKeysInTransactions) {
        Cache.remove(cacheKey);
      }
    }
  }
  
  public void commit() {
    if (mTransaction != null && mTransaction.isActive()) {
      try {
        mTransaction.commit();
      } catch (Exception e) {
        if (mCacheKeysInTransactions != null) {
          for (Object cacheKey : mCacheKeysInTransactions) {
            Cache.remove(cacheKey);
          }
        }
      }
    }
  }
  
  public void close() {
    if (mPersistenceManager != null) {
      mPersistenceManager.close();
      mPersistenceManager = null;
    }
  }
  
  public boolean isOpen() {
    return getCurrentTransaction().isActive();
  }
  
}
